﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Reflection;
using System.ComponentModel;


namespace CommonInteractive.Config
{

    [DisplayName("Initializer by default")]
    [Description("Create the section of configuration")]
    [DesignerCategory(Config.Initializer)]
    public class ConfigGenerator<T> : Config, IGenerate<T>
        where T : ConfigurationSection, new()    
    {


        protected Configuration Configuration;


        public void Load(string filename) 
        {
            Configuration = GetConfiguration(filename);
        }


        public void GenerateSection()
        {
            Generate();
            Configuration.Save(ConfigurationSaveMode.Full);
        }

        protected virtual void Generate()
        {
            ConfigurationSection section = GetOrCreateIfNotExists();


            using (ResolveAssembly resolve = GetResolver())
            {
                
                InitializeSectionWithDefaultValue(section);
            }
        }        

        protected ConfigurationSection GetOrCreateIfNotExists()
        {
            return GetOrCreateIfNotExists(typeof(T));
        }

        protected ConfigurationSection GetOrCreateIfNotExists(Type type)
        {

            using (ResolveAssembly resolve = GetResolver())
            {
                ConfigurationSection section;
                string name = GetDefaultName(type, out section);
                ConfigurationSection section2 = GetSection(name);

                if (section2 == null)
                {
                    Configuration.Sections.Add(name, section);
                    section.SectionInformation.ForceSave = true;
                    return section;
                }

                return section;

            }
        }

        private static ResolveAssembly _resolveAssembly;
        protected ResolveAssembly GetResolver()
        {
            ResolveAssembly a = _resolveAssembly ?? (_resolveAssembly = new ResolveAssembly(true, assemblies));
            a.Start();
            return a;
        }

        protected ConfigurationSection CreateSection(Type type)
        {
            ConfigurationSection c = Activator.CreateInstance(type) as ConfigurationSection;
            return c;
        }

        protected ConfigurationSection GetSection(string defaultName)
        {

                try
                {
                    ConfigurationSection ret = Configuration.GetSection(defaultName);
                    return ret;

                }
                catch (Exception ex)
                {
                    
                }
            return null;

        }


        public string DefaultName { get; set; }

        protected string GetDefaultName(Type type, out ConfigurationSection section)
        {
            section = Activator.CreateInstance(type) as ConfigurationSection;

            if (!string.IsNullOrEmpty(DefaultName))
                return DefaultName;

            FieldInfo m = type.GetField("DefaultName");
            string defaultName = m.GetValue(section) as string;
            return defaultName;
        }

        public IEnumerable<Assembly> assemblies;



        #region DefaultValue

        protected void InitializeSectionWithDefaultValue<U>(U section) where U : ConfigurationSection
        {


            foreach (PropertyInfo item in section.GetType().GetProperties())
            {

                try
                {

                    var i = item.GetValue(section, null);
                    
                    if (i is ConfigurationElement)
                        InitializeElementWithDefaultValue(i as ConfigurationElement);
                    
                }
                catch (Exception)
                {

                }
            }

        }

                
        private void InitializeElementWithDefaultValue<U>(U element) where U : ConfigurationElement
        {


            if (element.ElementInformation.IsCollection)
                return;


            foreach (object item in element.ElementInformation.Properties)
                if (item is PropertyInformation)
                {
                    PropertyInformation i2 = item as PropertyInformation;
                    var hh = i2.DefaultValue;

                    if (hh != null)
                    {
                        try
                        {
                            i2.Value = hh;
                        }
                        catch (Exception)
                        {

                        }

                    }
                }
            


           

            foreach (PropertyInfo item in element.GetType().GetProperties())
            {

                try
                {
                    var i = item.GetValue(element, null);
                   
                    if (i is ConfigurationElement)
                        InitializeElementWithDefaultValue(i as ConfigurationElement);

                }
                catch (Exception)
                {
                    
                }

            }

        }
      
        
        #endregion
  
    }


}
